home *** CD-ROM | disk | FTP | other *** search
/ Resource Library: Multimedia / Resource Library: Multimedia.iso / sgml / msdos / sgml07 / sgmlio.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-03-27  |  6.8 KB  |  284 lines

  1. /* sgmlio.c -
  2.    IO functions for core parser.
  3.  
  4.    Written by James Clark (jjc@jclark.com).
  5. */
  6.  
  7. /* SGML must see a file in which records start with RS and end with
  8.    RE, and EOFCHAR (Ctl-Z) is present at the end.  This module must
  9.    supply these characters if they are not naturally present in the
  10.    file.  SGML will open two files at a time: when an entity is
  11.    nested, the new file is opened before closing the old in order to
  12.    make sure the open is successful. If it is, the original open file
  13.    is closed temporarily (IOPEND); when the stack is popped, the new
  14.    file is closed and the original file is re-opened (IOCONT). SGML
  15.    will check error returns for the initial open of a file and all
  16.    reads, and for re-openings when the stack is popped, but not for
  17.    closes.  Returning <0 indicates an error; 0 or more is a successful
  18.    operation, except for IOREAD where the return value is the number
  19.    of characters read, and must exceed 0 to be successful.  The first
  20.    READ must always be successful, and normally consists of just
  21.    priming the buffer with EOBCHAR (or RS EOBCHAR).  SGMLIO must
  22.    assure that there is an EOBCHAR at the end of each block read,
  23.    except for the last block of the entity, which must have an
  24.    EOFCHAR.
  25.  
  26.    SGML views an entity as a contiguous whole, without regard to its
  27.    actual form of storage.  SGMLIO supports entities that are
  28.    equivalent to a single file of one or more records, or to a
  29.    concatenation of files.
  30. */
  31.  
  32. /* Uses only stream I/O.  This module should be portable to most ANSI
  33.    systems. */
  34. /* We try to ensure that if an IO operation fails, then errno will contain
  35.    a meaningful value (although it may be zero.) */
  36.  
  37. #include "config.h"
  38. #ifdef HAVE_O_NOINHERIT
  39. #include <fcntl.h>
  40. #include <io.h>
  41. #endif /* HAVE_O_NOINHERIT */
  42.  
  43. #include "sgmlaux.h"          /* Include files for auxiliary functions.. */
  44.  
  45. #ifdef HAVE_O_NOINHERIT
  46. #define FOPENR(file) nifopen(file)
  47. FILE *nifopen P((char *));
  48. #else /* not HAVE_O_NOINHERIT */
  49. #define FOPENR(file) fopen((file), "r")
  50. #endif /* not HAVE_O_NOINHERIT */
  51.  
  52. struct iofcb {                /* I/O file control block. */
  53.      FILE *fp;              /* File handle. */
  54.      long off;                /* Offset in file of current read block. */
  55.      char *next;              /* Next file (NULL if no more). */
  56.      char *file;              /* Current file (no length byte). */
  57.      int sverrno;          /* Saved value of errno. */
  58.      char bol;                  /* Non-zero if currently at beginning of line. */
  59.      char first;          /* Non-zero if the first read.  */
  60.      char wasbol;          /* Non-zero if current block was at beginning of line. */
  61. };
  62.  
  63. static char *lastfile;          /* The name of the last file closed. */
  64. static int bufsize;          /* Size of buffer passed to ioread(). */
  65. static char isbad[256];          /* Table of chars that will be turned into BADCHAR. */
  66.  
  67. static char *nextstr();          /* Iterate over list of strings. */
  68.  
  69. VOID ioinit(swp)
  70. struct switches *swp;
  71. {
  72.      isbad[BADCHAR] = 1;
  73.      isbad[RECHAR] = 1;
  74.      isbad[EOBCHAR] = 1;
  75.      isbad[EOFCHAR] = 1;
  76.      isbad[EOS] = 1;
  77.      isbad[(UNCH)swp->delnonch] = 1;
  78.      isbad[(UNCH)GENRECHAR] = 1;
  79.      bufsize = swp->swbufsz;
  80. }
  81.  
  82. int ioopen(id, pp)
  83. UNIV id;
  84. UNIV *pp;
  85. {
  86.      struct iofcb *f;
  87.      char *s;
  88.      errno = 0;
  89.      if (!id)
  90.       return -1;
  91.      s = id;
  92.      if (!*s)
  93.       return -1;
  94.      f = (struct iofcb *)rmalloc((UNS)sizeof(struct iofcb));
  95.      f->file = s;
  96.      f->next = nextstr(s);
  97.      errno = 0;
  98.      f->fp = FOPENR(f->file);
  99.      f->bol = 1;
  100.      f->first = 1;
  101.      *pp = (UNIV)f;
  102.      return f->fp ? 1 : -1;
  103. }
  104.  
  105. VOID ioclose(p)
  106. UNIV p;
  107. {
  108.      struct iofcb *f = (struct iofcb *)p;
  109.      fclose(f->fp);
  110.      lastfile = f->file;
  111.      frem((UNIV)f);
  112. }
  113.  
  114. VOID iopend(p, off)
  115. UNIV p;
  116. int off;
  117. {
  118.      struct iofcb *f = (struct iofcb *)p;
  119.      f->bol = 0;
  120.      if (f->wasbol) {
  121.       if (off == 0)
  122.            f->bol = 1;
  123.       else
  124.            off--;
  125.      }
  126.      errno = 0;
  127.      /* f->off will be checked in iocont. */
  128.      if (fseek(f->fp, f->off, SEEK_SET))
  129.       f->off = -1L;
  130.      else {
  131.       /* Avoid relying on position arithmetic. */
  132.       int c = EOF;
  133.       while (--off >= 0)
  134.            c = getc(f->fp);
  135.       f->off = ftell(f->fp);                  /* Save location. */
  136.       if (c == '\n')
  137.            f->bol = 1;
  138.      }
  139.      fclose(f->fp);
  140.      f->sverrno = errno;
  141. }
  142.  
  143. int iocont(p)
  144. UNIV p;
  145. {
  146.      struct iofcb *f = (struct iofcb *)p;
  147.      if (f->off == -1L) {
  148.       errno = f->sverrno;
  149.       return -1;
  150.      }
  151.      errno = 0;
  152.      f->fp = FOPENR(f->file);
  153.      if (f->fp) {
  154.       errno = 0;
  155.       return fseek(f->fp, f->off, SEEK_SET) ? -1 : 0;
  156.      }
  157.      else
  158.       return -1;
  159. }
  160.  
  161. /* Return -1 on error, otherwise the number of bytes read.  The
  162. strategy is to concatenate the files, insert a RS at the beginning of
  163. each line, and change each '\n' into a RE.  The returned data
  164. shouldn't cross a file boundary, otherwise error messages might be
  165. inaccurate.  The first read must always succeed. */
  166.  
  167. int ioread(p, buf, newfilep)
  168. UNIV p;
  169. UNCH *buf;
  170. int *newfilep;
  171. {
  172.      int i = 0;
  173.      struct iofcb *f = (struct iofcb *)p;
  174.      FILE *fp;
  175.      int c;
  176.      
  177.      *newfilep = 0;
  178.      if (f->first) {
  179.       buf[i] = EOBCHAR;
  180.       f->first = 0;
  181.       return 1;
  182.      }
  183.      fp = f->fp;
  184.      for (;;) {
  185.       errno = 0;
  186.       f->off = ftell(fp);
  187.       if (f->off == -1L)
  188.            return -1;
  189.       errno = 0;
  190.       c = getc(fp);
  191.       if (c != EOF)
  192.            break;
  193.       if (ferror(fp))
  194.            return -1;
  195.       if (fclose(fp) == EOF)
  196.            return -1;
  197.       if (!f->next){
  198.            buf[0] = EOFCHAR;
  199.            return 1;
  200.       }
  201.       f->file = f->next;
  202.       f->next = nextstr(f->next);
  203.       *newfilep = 1;
  204.       errno = 0;
  205.       fp = f->fp = FOPENR(f->file);
  206.       if (!fp)
  207.            return -1;
  208.       f->bol = 1;
  209.      }
  210.      if (f->bol) {
  211.       f->bol = 0;
  212.       buf[i++] = RSCHAR;
  213.       f->wasbol = 1;
  214.      }
  215.      else
  216.       f->wasbol = 0;
  217.      errno = 0;
  218.      for (;;) {
  219.       if (c == '\n') {
  220.            f->bol = 1;
  221.            buf[i++] = RECHAR;
  222.            break;
  223.       }
  224.       if (isbad[c])
  225.            c = BADCHAR;
  226.       buf[i++] = c;
  227.       if (i >= bufsize - 1)
  228.            break;
  229.       c = getc(fp);
  230.       if (c == EOF) {
  231.            if (ferror(fp))
  232.             return -1;
  233.            /* This is in the middle of a line. */
  234.            break;
  235.       }
  236.      }
  237.      buf[i++] = EOBCHAR;
  238.      return i;
  239. }
  240.  
  241. static char *nextstr(p)
  242. char *p;
  243. {
  244.      p = strchr(p, '\0');
  245.      return *++p ? p : 0;
  246. }
  247.  
  248. /* Return the filename associated with p.  If p is NULL, return the filename
  249. of the last file closed. */
  250.  
  251. char *ioflid(p)
  252. UNIV p;
  253. {
  254.      if (!p)
  255.       return lastfile;
  256.      return ((struct iofcb *)p)->file;
  257. }
  258.  
  259. #ifdef HAVE_O_NOINHERIT
  260.  
  261. /* This is the same as fopen(name, "r") except that it tells DOS that
  262. the file descriptor should not be inherited by child processes.  */
  263.  
  264. FILE *nifopen(name)
  265. char *name;
  266. {
  267.      int fd = open(name, O_RDONLY|O_NOINHERIT|O_TEXT);
  268.      if (fd < 0)
  269.       return 0;
  270.      return fdopen(fd, "r");
  271. }
  272.  
  273. #endif /* HAVE_O_NOINHERIT */
  274.  
  275. /*
  276. Local Variables:
  277. c-indent-level: 5
  278. c-continued-statement-offset: 5
  279. c-brace-offset: -5
  280. c-argdecl-indent: 0
  281. c-label-offset: -5
  282. End:
  283. */
  284.